package com.hontech.bvapp2.device.cp

import com.hontech.bvapp2.device.Address
import com.hontech.bvapp2.device.DeviceConn
import com.hontech.bvapp2.device.Frame
import com.hontech.bvapp2.utils.ExecException
import com.hontech.bvapp2.utils.hex16
import com.hontech.bvapp2.utils.isBitSet
import com.hontech.bvapp2.utils.postEvent
import okhttp3.internal.format
import serial.codec.Uint16
import serial.codec.Uint8
import serial.codec.u16
import serial.codec.u32
import serial.codec.u8

private const val STIR_CAP = 0x04
private const val STIR_MOTOR = 0x05
private const val PARTS_CTRL = 0x06
private const val NOZZLE = 0x07
private const val ICE = 0x08
private const val DRAW_HEAT_CTRL = 0x09
private const val SET_ARG = 0x0A
private const val GET_ARG = 0x0B
private const val DRAW_WATER = 0x0C
private const val STEAM_CTRL = 0x0D
private const val CLAMP_CTRL = 0x0E
private const val TRUN_CTRL = 0x0F

object Heat {

    suspend fun clampCtrl(ctrl: Int) {
        DeviceConn.req(
            Address.HEAT,
            CLAMP_CTRL,
            ctrl.u8()
        ).parse()
    }

    suspend fun trunCtrl(ctrl: Int) {
        DeviceConn.req(
            Address.HEAT,
            TRUN_CTRL,
            ctrl.u8()
        ).parse()
    }

    suspend fun iceReset() {
        ice(0x05, 0, 0)
    }

    suspend fun iceStop() {
        ice(0x06, 0, 0)
    }

    suspend fun iceDrop() {
        ice(0x07, 0, 0)
    }

    suspend fun drawIce(g: Int) {
        val result = ice(0x0A, g shr 8, g)
        if ((result.data2 == 0xFF) && (result.data1 == 0xFF)) {
            throw IllegalStateException("上次出冰没有结束")
        }
    }

    class DrawIceInfo (
        val step: String,
        val num: Int,
        val isFinish: Boolean
    )

    suspend fun drawIceProg(): DrawIceInfo {
        val result = ice(0x1A, 0, 0)
        val info = when (result.data1) {
            0 -> DrawIceInfo("未出冰", result.data2, true)
            1 -> DrawIceInfo("正在出冰", result.data2, false)
            2 -> DrawIceInfo("出冰完成,设备处于检测阶段", result.data2, true)
            3 -> DrawIceInfo("出冰完成,监测结束,出冰门故障", result.data2, true)
            4 -> DrawIceInfo("出冰完成,检测结束,无故障", result.data2, true)
            else -> throw IllegalStateException("未知状态:${result.data1}")
        }
        return info
    }

    suspend fun drawWater(id: Int, value: Int) {
        DeviceConn.req(
            Address.HEAT,
            DRAW_WATER,
            id.u8(),
            value.u16()
        ).parse()
    }

    suspend fun steamCtrl(ctrl: Int) {
        DeviceConn.simpleReq(
            Address.HEAT,
            STEAM_CTRL,
            ctrl.u8()
        ).parse()
    }

    suspend fun setArg(id: Int, arg: Int) {
        DeviceConn.simpleReq(
            Address.HEAT,
            SET_ARG,
            id.u8(),
            arg.u16()
        ).parse()
    }

    suspend fun getArg(id: Int): Int {
        val arg = Uint16()
        DeviceConn.simpleReq(
            Address.HEAT,
            GET_ARG,
            id.u8()
        ).parse(arg)
        return arg.value
    }

    suspend fun drawHeatCtrl(ctrl: Int) {
        DeviceConn.simpleReq(
            Address.HEAT,
            DRAW_HEAT_CTRL,
            ctrl.u8(),
        ).parse()
    }

    suspend fun queryIceOtherStatus(): String {
        val r11 = ice(0x11, 0, 0)
        val r12 = ice(0x12, 0, 0)
        val r13 = ice(0x13, 0, 0)
        val r14 = ice(0x14, 0, 0)
        val r15 = ice(0x15, 0, 0)
        val r16 = ice(0x16, 0, 0)
        val r17 = ice(0x17, 0, 0)
        val r18 = ice(0x18, 0, 0)
        val r19 = ice(0x19, 0, 0)

        val sb = StringBuilder()
        sb.appendLine("环境温度:${r11.decodeF16()}℃")
        sb.appendLine("蒸发器温度:${r12.decodeF16()}℃")
        sb.appendLine("冷凝器温度:${r13.decodeF16()}℃")
        sb.appendLine("马达电流:${r14.decodeF16()}A")
        sb.appendLine("压缩机电流:${r15.decodeF16()}A")
        sb.appendLine("上液位浮球计数:${r16.data2}")
        sb.appendLine("软件版本号:${r17.decodeU16().hex16()}")
        sb.appendLine("最近一次报警:${r18.data2}")
        sb.appendLine("下浮球:${r19.data2.isBitSet(0)} 上浮球:${r19.data2.isBitSet(1)} 满冰常开:${r19.data2.isBitSet(2)} 满冰常闭:${r19.data2.isBitSet(3)}")

        return sb.toString()
    }

    suspend fun queryIceStatus(): String {
        val result = ice(0x10, 0, 0)
        return when (result.data1) {
            0x01 -> "设备状态正常，压缩机工作中"
            0x02 -> "设备状态正常，压缩机停止中:${result.data2}"
            0x11 -> "设备状态正常，压缩机工作中，满冰"
            0x12 -> "设备状态正常，压缩机停止中，满冰:${result.data2}"
            0xE1 -> "缺水故障"
            0xE2 -> "排水故障"
            0xE3 -> "环境低温报警"
            0xE4 -> "环境高温报警"
            0xE5 -> "冷凝温度高温报警"
            0xE6 -> "蒸发器过冷报警"
            0xE7 -> "马达故障"
            0xEA -> "压缩机故障"
            0xEB -> "压缩机故障，重新上电复位"
            0xEC -> "马达故障，重新上电复位"
            else -> throw IllegalStateException("未知状态${result.data1} ${result.data2}")
        }
    }

    class IceResult(val cmd2: Int, val data1: Int, val data2: Int) {
        fun decodeU16() = (data1 shl 8) or  data2
        fun decodeF16() = format("%.1f", decodeI16() * 0.1f)
        private fun decodeI16(): Int {
            val value = decodeU16()
            if ((value and 0x8000) != 0) {
                return -(0x10000 - value)
            }
            return value
        }
    }

    suspend fun ice(cmd2: Int, data1: Int, data2: Int): IceResult {
        val c2 = Uint8()
        val d1 = Uint8()
        val d2 = Uint8()
        DeviceConn.simpleReq(Address.HEAT, ICE, cmd2.u8(), data1.u8(), data2.u8())
            .parse(c2, d1, d2)
        return IceResult(c2.value, d1.value, d2.value)
    }

    suspend fun nozzleCtrl(p: Int) {
        DeviceConn.req(
            Address.HEAT,
            NOZZLE,
            p.u32()
        ).parse()
    }

    suspend fun stirMotorCtrl(ctrl: Int) {
        DeviceConn.simpleReq(
            Address.HEAT,
            STIR_MOTOR,
            ctrl.u8()
        ).parse()
    }

    suspend fun stirCapCtrl(ctrl: Int) {
        DeviceConn.req(
            Address.HEAT,
            STIR_CAP,
            ctrl.u8()
        ).parse()
    }

    suspend fun partsCtrl(id: Int, ctrl: Int) {
        DeviceConn.simpleReq(
            Address.HEAT,
            PARTS_CTRL,
            id.u8(),
            ctrl.u8()
        ).parse()
    }

    fun onStatus(frame: Frame) {
        val version = Uint16()
        val waterTemp = Uint16()
        val steamTemp = Uint16()
        val sensor = Uint16()
        val analog = Uint16()
        val ctrlFlag = Uint16()
        val flowCount = Uint16()
        val drawState = Uint8()
        val waterHeatState = Uint8()
        val steamHeatState = Uint8()
        frame.parse(version, waterTemp, steamTemp, sensor, analog, ctrlFlag, flowCount, drawState, waterHeatState, steamHeatState)
        val s = Status(
            version.value,
            waterTemp.signedValue(),
            steamTemp.signedValue(),
            sensor.value,
            analog.value,
            ctrlFlag.value,
            flowCount.value,
            drawState.value,
            waterHeatState.value,
            steamHeatState.value,
        )
        postEvent(s)
        status = s
    }

    var status: Status? = null
        private set

    class Status(
        val version: Int,
        val waterTemp: Int,
        val steamTemp: Int,
        val sensor: Int,
        val analog: Int,
        val ctrlFlag: Int,
        val flowCount: Int,
        val drawState: Int,
        val waterHeatState: Int,
        val steamHeatState: Int,
    ) {

        fun version() = version.hex16()

        fun pearlChecked() = sensor.isBitSet(0)
        fun nozzleOrigin() = sensor.isBitSet(1)
        fun stirTop() = sensor.isBitSet(2)
        fun stirBottom() = sensor.isBitSet(3)
        fun trunLeft() = sensor.isBitSet(4)
        fun trunRight() = sensor.isBitSet(5)
        fun clampLeft() = sensor.isBitSet(6)
        fun clampRight() = sensor.isBitSet(7)
        fun nozzleAlm() = sensor.isBitSet(8)
        fun waterHigh() = sensor.isBitSet(9)
        fun waterLow() = sensor.isBitSet(10)
        fun tempFail() = sensor.isBitSet(11)

        fun steamHeat() = ctrlFlag.isBitSet(0)
        fun waterHeat() = ctrlFlag.isBitSet(1)
        fun v3() = ctrlFlag.isBitSet(2)
        fun v4() = ctrlFlag.isBitSet(3)
        fun pump2() = ctrlFlag.isBitSet(4)
        fun pump1() = ctrlFlag.isBitSet(5)
        fun v6() = ctrlFlag.isBitSet(6)
        fun v7() = ctrlFlag.isBitSet(7)
        fun v2() = ctrlFlag.isBitSet(8)
        fun v1() = ctrlFlag.isBitSet(9)
        fun clampV() = ctrlFlag.isBitSet(10)
        fun trunV() = ctrlFlag.isBitSet(11)
        fun waterPump() = ctrlFlag.isBitSet(12)
        fun steamPump() = ctrlFlag.isBitSet(13)
        fun v8() = ctrlFlag.isBitSet(14)
        fun air() = ctrlFlag.isBitSet(15)

        fun drawState(): String {
            return when(drawState) {
                0 -> "停止"
                1 -> "工作"
                2 -> "超时"
                else -> "未知:$drawState"
            }
        }

        fun waterHeatState(): String {
            return when(waterHeatState) {
                0 -> "空闲"
                1 -> "停止"
                2 -> "加热/保温"
                3 -> "故障"
                4 -> "超时"
                else -> "未知:$waterHeatState"
            }
        }

        fun steamHeatState(): String {
            return when(steamHeatState) {
                0 -> "停止"
                1 -> "故障"
                2 -> "超时"
                3 -> "泄压"
                4 -> "预热"
                5 -> "注蒸汽"
                else -> "未知:$steamHeatState"
            }
        }

    }


}

